#!/usr/bin/env python3

###############################################################################
# Name:        py3func.py
# Purpose:     usual functions of python3 code
# Author:      Bright Li
# Modified by:
# Created:     2018-08-31
# Version:     [0.0.4]
# RCS-ID:      $$
# Copyright:   (c) Bright Li
# Licence:
###############################################################################

import os, sys
import re
import shutil
import socket

''' 日志消息 '''
import logging

LOG_LEVEL = logging.DEBUG
def make_logging(name, level = None, output_file = None):
    if level is None:
        level = LOG_LEVEL
    logger = logging.getLogger(name)
    logger.setLevel(level)
    if output_file is None:
        handler = logging.StreamHandler()
    else:
        handler = logging.FileHandler(output_file)
    handler.setLevel(level)
    # 处理 path_name
    _, name = os.path.split(name)
    # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    formatter = logging.Formatter('[%(name)s - %(levelname)s] %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    return logger


''' 字典排序 '''
def func_dict_sort(dict_, sort_type):
    """ return a list of sorted """
    if sort_type == "ascii":
        return [(key, dict_[key]) for key in sorted(dict_.keys())]
    elif sort_type == "value":
        list_items_charge = [(tuple_[1], tuple_[0]) for tuple_ in dict_.items()]
        return [(key[1], key[0]) for key in sorted(list_items_charge)]


""" 文件夹递归遍历函数 """
import os

def walk_dir(path, topdown=True):
    list_files = []
    for root, dirs, files in os.walk(path, topdown):
        for filepath in files:
            list_files.append(os.path.join(root, filepath))
    return list_files


''' 运行时间 '''
import time

def diff_clock(last_time):
    ''' return current time '''
    now = time.clock()
    logging.debug('Now : %f' % now)
    logging.debug('Time from last socket : %d' % (now - last_time))
    return now


''' hex bytes 打印 '''
HEXA_FILTER = ''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])

def isAscii(str_src: str):
    """
    0x07    '\a'
    ...
    0x09    '\t'
    0x0A    '\n'
    ...
    0x0D    '\r'
    0x20    SPACE
    0x7F    DEL
    """
    ascii_condition = lambda char : (ord(char) >= 0x07 and ord(char) <= 0x0D) or \
                                    (ord(char) >= 0x20 and ord(char) < 0x7F)
    if len(str_src) == 1:
        return ascii_condition(str_src)
    # elif len(str_src) > 1:
    for char in str_src:
        if not ascii_condition(char):
            logging.error("The unicode-char is not ascii: %s -- %s" % (char, hex(ord(char))))
            return False
    return True

def hexdump(src, length=8):
    result = []
    digits = 2 if isAscii(src) else 4
    for i in range(0, len(src), length):
        piece = src[i:i+length]
        hexa = ' '.join(["%0*X" % (digits, ord(x)) for x in piece])
        text = piece.translate(HEXA_FILTER)
        result.append("%04X   %-*s   %s\n" % (i, length*(digits + 1), hexa, text))
    return ''.join(result)


''' 编译项目 '''
import compileall

def make_pyc(src_dir, rstr_rx=None, force=True):
    rx = re.compile(rstr_rx) if rstr_rx else None
    if not compileall.compile_dir(src_dir,
            force=force,  # 强制刷新之前的编译文件
            rx=rx,  # 需要通过正则表达式忽略的文件，例如 re.compile(r"test.*")
            quiet=1,  # 1: 只显示错误信息; 0: 显示全部信息; 2: 不显示
            legacy=False):  # True: 本地生成同名的 *.pyc 文件
        raise Exception("Something wrong when ompile the python-file dir")

def extract_pyc(src_dir, dest_dir):
    # 递归搜集 __pychache__ 目录的 pyc 文件
    # os.walk() 函数如果是后序遍历，则每层结构都是先更新了__pychache__文件
    # 名称后，才处理其父目录；否则则需要重新从顶层遍历目录后执行下述代码
    for root, dirs, files in os.walk(src_dir):
        _, dir_name = os.path.split(root)
        if dir_name == "__pycache__":
            # 替换 *.pyc 文件名称
            for file_name in files:
                # rename the xxx.cpython-34.pyc files
                if re.search('.cpython-[0-9]+\.pyc$', file_name):
                    list_name = file_name.split('.')
                    del list_name[1]
                    os.rename(os.path.join(root, file_name),
                            os.path.join(root, '.'.join(list_name)))

    # 移动 __pycache__ 目录
    if os.path.isdir(dest_dir):
        logging.info("目标目录已存在，删除并更新目录")
        shutil.rmtree(dest_dir)
    shutil.move(os.path.join(src_dir, "__pycache__"), dest_dir)
    for root, dirs, files in os.walk(src_dir):
        if "__pycache__" in dirs:
            relative_path = root.lstrip(src_dir)
            shutil.move(os.path.join(root, "__pycache__"),
                        os.path.join(dest_dir, relative_path))
